#include "app_main.h"

#include <main.h>
#include <stdio.h>
#include <string.h>

#include "bsp_nm25q128.h"
#include "app_debug_printf.h"
#include "app_at24c02.h"
#include "app_flash.h"
#include "app_uart1.h"
#include "app_nm25q128.h"

#define EV_EXECUTE_APP (0x00000001)
#define EV_DOWNLOAD_FIRM (0x00000002)
#define EV_LOAD_FIRM (0x00000004)

#define SOH (0x01)
#define EOT (0x04)

typedef void (*reset_func)(void);
reset_func reset;

uint32_t event_group = 0;

void set_msp(uint32_t addr)
{
	__asm__ volatile(
		"MSR MSP, %0" /* 将参数addr写入MSP */
		:			  /* 没有输出操作数 */
		: "r"(addr)	  /* 输入操作数：将addr放入任意通用寄存器 */
		: "memory"	  /* 告诉编译器这条指令可能修改内存 */
	);
}

void execute_app(uint32_t addr)
{
	set_msp(*(uint32_t *)addr);

	reset = (reset_func) * (uint32_t *)(addr + 4);
	reset();
}

uint16_t compute_xmodem_crc16(uint8_t *data, uint32_t len)
{
	uint16_t poly = 0x1021;
	uint16_t crc = 0;

	for (uint32_t i = 0; i < len; ++i)
	{
		crc ^= ((uint16_t)data[i]) << 8;

		for (uint8_t j = 0; j < 8; ++j)
		{
			if (crc & 0x8000)
			{
				crc = (crc << 1) ^ poly;
			}
			else
			{
				crc <<= 1;
			}

			crc &= 0xffff;
		}
	}

	return crc;
}

void option_menu(void)
{
	debug_printf("\r\n-----输入[x]选择对应选项-----\r\n");
	debug_printf("->[a]:退出并执行A区\r\n");
	debug_printf("->[b]:下载固件到外部flash\r\n");
	debug_printf("->[c]:加载固件到片上flash\r\n");

	uart1_rx_frame_t frame;
	while (1)
	{
		if (uart1_rx_frame_dequeue(&frame))
		{
			debug_printf("你输入了[%c]\r\n", uart1_rx_cb.buf[frame.start]);
			switch (uart1_rx_cb.buf[frame.start])
			{
			case 'a':
				event_group |= EV_EXECUTE_APP;
				return;

			case 'b':
				event_group |= EV_DOWNLOAD_FIRM;
				return;

			case 'c':
				event_group |= EV_LOAD_FIRM;
				return;

			default:
				debug_printf("输出错误\r\n");
				return;
			}
		}
	}
}

uint8_t xmodem_receive_data(nm25q128_part_t nm25q128_part)
{
	uart1_rx_frame_t frame;
	debug_printf("等待Xmodem中，输入任意键退出……\r\n");
	while (1)
	{
		debug_printf("C");
		if (uart1_rx_frame_dequeue(&frame))
		{
			break;
		}
		HAL_Delay(1000);
	}

	uint32_t data_len;
	uint32_t receive_size = 0;
	uint32_t addr = nm25q128_part_addr_base[nm25q128_part];
	while (1)
	{
		data_len = frame.end - frame.start + 1;
		if (data_len == 133 && uart1_rx_cb.buf[frame.start] == SOH)
		{
			if (compute_xmodem_crc16(&uart1_rx_cb.buf[frame.start + 3], 128) ==
				((uint16_t)uart1_rx_cb.buf[frame.end - 1] << 8) + uart1_rx_cb.buf[frame.end])
			{
				receive_size += 128;
				if (receive_size <= nm25q128_part_size[nm25q128_part])
				{
					if (addr % 0x1000 == 0)
					{
						nm25q128_erase_sector(addr);
					}

					nm25q128_page_program(addr, &uart1_rx_cb.buf[frame.start + 3], 128);
					addr += 128;
				}
				else
				{
					debug_printf("错误，固件大小超出范围\r\n");
					return 0;
				}

				debug_printf("\x06");
			}
			else
			{
				debug_printf("\x15");
				continue;
			}
		}
		else if (data_len == 1 && uart1_rx_cb.buf[frame.start] == EOT)
		{
			at24c02_content.nm25q128_part_size[nm25q128_part] = receive_size;
			at24c02_update_content();
			return 1;
		}
		else
		{
			return 0;
		}

		while (!uart1_rx_frame_dequeue(&frame))
		{
		}
	}
}

void download_frimware_option(void)
{
	debug_printf("\r\n-----输入[x]选择下载到对应分区-----\r\n");
	debug_printf("->[a]:退出\r\n");
	debug_printf("->[b]:FIRMWARE_OTA分区\r\n");
	debug_printf("->[c]:FIRMWARE_1分区\r\n");
	debug_printf("->[d]:FIRMWARE_2分区\r\n");
	debug_printf("->[e]:APP_ASSET分区\r\n");

	uart1_rx_frame_t frame;
	while (1)
	{
		if (uart1_rx_frame_dequeue(&frame))
		{
			debug_printf("你输入了[%c]\r\n", uart1_rx_cb.buf[frame.start]);
			switch (uart1_rx_cb.buf[frame.start])
			{
			case 'a':
				return;

			case 'b':
				xmodem_receive_data(FIRMWARE_OTA);
				return;

			case 'c':
				xmodem_receive_data(FIRMWARE_1);
				return;

			case 'd':
				xmodem_receive_data(FIRMWARE_2);
				return;

			case 'e':
				xmodem_receive_data(APP_ASSET);
				return;

			default:
				debug_printf("输入错误\r\n");
				return;
			}
		}
	}
}

uint8_t load_firmware(nm25q128_part_t nm25q128_part)
{
	uint8_t buf[65536];
	memset(buf, 0, sizeof(buf));

	uint32_t firmware_size = at24c02_content.nm25q128_part_size[nm25q128_part];

	if (firmware_size != 0 && 0 == firmware_size % 4)
	{
		debug_printf("擦除A区中……\r\n");
		if (!flash_parta_erase())
		{
			debug_printf("擦除失败\r\n");
			return 0;
		}
		debug_printf("擦除成功\r\n");

		debug_printf("加载固件中……\r\n");

		uint16_t i = 0;
		for (i = 0; i < firmware_size / sizeof(buf); ++i)
		{
			nm25q128_read_data(nm25q128_part_addr_base[nm25q128_part] + i * sizeof(buf),
							   buf,
							   sizeof(buf));
			flash_program(flash_sector_base_addr[FLASH_PARTA_START_SECTOR] + i * sizeof(buf),
						  (uint32_t *)buf,
						  sizeof(buf) / sizeof(uint32_t));
		}

		if (firmware_size % sizeof(buf) != 0)
		{
			nm25q128_read_data(nm25q128_part_addr_base[nm25q128_part] + i * sizeof(buf),
							   buf,
							   firmware_size % sizeof(buf));
			flash_program(flash_sector_base_addr[FLASH_PARTA_START_SECTOR] + i * sizeof(buf),
						  (uint32_t *)buf,
						  firmware_size % sizeof(buf) / sizeof(uint32_t));
		}

		debug_printf("固件已加载\r\n");
	}
	else
	{
		debug_printf("固件大小错误\r\n");
		return 0;
	}

	return 1;
}

void load_firmware_option()
{
	debug_printf("\r\n-----输入[x]选择加载对应分区的固件-----\r\n");
	debug_printf("->[a]:退出\r\n");
	debug_printf("->[b]:FIRMWARE_OTA分区\r\n");
	debug_printf("->[c]:FIRMWARE_1分区\r\n");
	debug_printf("->[d]:FIRMWARE_2分区\r\n");

	uart1_rx_frame_t frame;
	while (1)
	{
		if (uart1_rx_frame_dequeue(&frame))
		{
			debug_printf("你输入了[%c]\r\n", uart1_rx_cb.buf[frame.start]);
			switch (uart1_rx_cb.buf[frame.start])
			{
			case 'a':
				return;

			case 'b':
				load_firmware(FIRMWARE_OTA);
				return;

			case 'c':
				load_firmware(FIRMWARE_1);
				return;

			case 'd':
				load_firmware(FIRMWARE_2);
				return;

			default:
				debug_printf("输入错误\r\n");
				return;
			}
		}
	}
}

void ota(void)
{
	if (at24c02_get_content() && at24c02_content.ota_flag == OTA_FLAG)
	{
		debug_printf("更新A区中……\r\n");

		if (load_firmware(FIRMWARE_OTA))
		{
			debug_printf("更新A区成功\r\n");
			debug_printf("执行A区……\r\n");
			execute_app(flash_sector_base_addr[FLASH_PARTA_START_SECTOR]);
		}
		else
		{
			debug_printf("更新A区失败\r\n");
		}
	}
}

void app_main(void)
{
	ota();
	uart1_rx_start();
	debug_printf("5秒内输入[space]进入选项菜单，否则将会执行A区……\r\n");

	uint16_t i = 0;
	uart1_rx_frame_t frame;
	for (i = 0; i < 1000; ++i)
	{
		if (uart1_rx_frame_dequeue(&frame) && uart1_rx_cb.buf[frame.start] == ' ')
		{
			break;
		}
		HAL_Delay(5);
	}

	if (i < 1000)
	{
		while (1)
		{
			option_menu();

			if (event_group & EV_EXECUTE_APP)
			{
				event_group &= ~EV_EXECUTE_APP;
				debug_printf("执行A区……\r\n");
				execute_app(flash_sector_base_addr[FLASH_PARTA_START_SECTOR]);
			}

			if (event_group & EV_DOWNLOAD_FIRM)
			{
				event_group &= ~EV_DOWNLOAD_FIRM;
				download_frimware_option();
			}

			if (event_group & EV_LOAD_FIRM)
			{
				event_group &= ~EV_LOAD_FIRM;
				load_firmware_option();
			}
		}
	}
	else
	{
		debug_printf("执行A区……\r\n");
		execute_app(flash_sector_base_addr[FLASH_PARTA_START_SECTOR]);
	}
}
